@workerdeck/ui 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/{SessionPanel-_U8tjX29.mjs → SessionPanel-CKQa4i0Y.mjs} +337 -269
- package/build/SessionPanel-CKQa4i0Y.mjs.map +1 -0
- package/build/{SessionPanel-CyhygZx_.d.mts → SessionPanel-CZMA44NM.d.mts} +73 -2
- package/build/format.d.mts +65 -1
- package/build/format.mjs +118 -1
- package/build/format.mjs.map +1 -0
- package/build/index.d.mts +129 -10
- package/build/index.mjs +461 -5
- package/build/index.mjs.map +1 -1
- package/build/workspace.d.mts +36 -1
- package/build/workspace.mjs +16 -2
- package/build/workspace.mjs.map +1 -1
- package/package.json +4 -4
- package/src/components/agent/Composer.tsx +18 -10
- package/src/components/agent/EngineIcon.tsx +97 -0
- package/src/components/agent/Loader.tsx +11 -46
- package/src/components/agent/Message.tsx +10 -6
- package/src/components/agent/QuestionPrompt.tsx +1 -1
- package/src/components/agent/SessionBrowser.tsx +546 -0
- package/src/components/agent/SessionPanel.tsx +89 -14
- package/src/components/agent/SessionWorkspace.tsx +45 -0
- package/src/components/agent/StatusBar.tsx +9 -2
- package/src/components/agent/ToolCallCard.tsx +11 -2
- package/src/components/agent/Transcript.tsx +28 -11
- package/src/components/agent/line-prompt.tsx +2 -2
- package/src/components/agent/pulse.tsx +60 -0
- package/src/components/agent/transcript-variant.tsx +62 -0
- package/src/components/ui/Menu.tsx +1 -1
- package/src/components/ui/Select.tsx +1 -1
- package/src/components/ui/Tooltip.tsx +1 -1
- package/src/format.ts +1 -0
- package/src/index.ts +12 -0
- package/src/lib/status.ts +124 -0
- package/src/styles/theme.css +45 -15
- package/build/SessionPanel-_U8tjX29.mjs.map +0 -1
|
@@ -134,7 +134,7 @@ const SelectContent = ({ className, align = "start", alignItemWithTrigger = fals
|
|
|
134
134
|
alignItemWithTrigger,
|
|
135
135
|
side,
|
|
136
136
|
sideOffset,
|
|
137
|
-
className: "isolate z-
|
|
137
|
+
className: "isolate z-80 outline-none",
|
|
138
138
|
children: /* @__PURE__ */ jsx(Select.Popup, {
|
|
139
139
|
"data-slot": "select-content",
|
|
140
140
|
className: cn("max-h-[min(24rem,var(--available-height))] min-w-[var(--anchor-width)] overflow-y-auto", "rounded-md border border-border bg-surface p-1 text-fg-1 shadow-(--shadow-lg) outline-none", className),
|
|
@@ -161,7 +161,7 @@ const MenuContent = ({ className, align = "end", side = "bottom", sideOffset = 6
|
|
|
161
161
|
align,
|
|
162
162
|
side,
|
|
163
163
|
sideOffset,
|
|
164
|
-
className: "isolate z-
|
|
164
|
+
className: "isolate z-80 outline-none",
|
|
165
165
|
children: /* @__PURE__ */ jsx(Menu.Popup, {
|
|
166
166
|
"data-slot": "menu-content",
|
|
167
167
|
className: cn("min-w-48 rounded-md border border-border bg-surface p-1 text-fg-1 shadow-(--shadow-lg) outline-none", "transition-[opacity,transform] duration-(--motion-base)", "data-starting-style:scale-95 data-starting-style:opacity-0", "data-ending-style:scale-95 data-ending-style:opacity-0", className),
|
|
@@ -239,7 +239,7 @@ const TooltipProvider = Tooltip.Provider;
|
|
|
239
239
|
const TooltipContent = ({ className, side = "top", sideOffset = 6, ...props }) => /* @__PURE__ */ jsx(Tooltip.Portal, { children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
|
|
240
240
|
side,
|
|
241
241
|
sideOffset,
|
|
242
|
-
className: "isolate z-
|
|
242
|
+
className: "isolate z-90",
|
|
243
243
|
children: /* @__PURE__ */ jsx(Tooltip.Popup, {
|
|
244
244
|
"data-slot": "tooltip-content",
|
|
245
245
|
className: cn("rounded-md border border-border bg-surface px-2 py-1 text-label text-fg-2 shadow-(--shadow-md) outline-none", className),
|
|
@@ -4280,6 +4280,78 @@ function hashtagTrigger(opts = {}) {
|
|
|
4280
4280
|
};
|
|
4281
4281
|
}
|
|
4282
4282
|
//#endregion
|
|
4283
|
+
//#region src/components/agent/transcript-variant.tsx
|
|
4284
|
+
const VariantContext = createContext("cards");
|
|
4285
|
+
function TranscriptVariantProvider({ value, children }) {
|
|
4286
|
+
return /* @__PURE__ */ jsx(VariantContext.Provider, {
|
|
4287
|
+
value,
|
|
4288
|
+
children
|
|
4289
|
+
});
|
|
4290
|
+
}
|
|
4291
|
+
function useTranscriptVariant() {
|
|
4292
|
+
return useContext(VariantContext);
|
|
4293
|
+
}
|
|
4294
|
+
/** True in `lines`, for the many `cond ? a : b` reads in the row components. */
|
|
4295
|
+
function useLines() {
|
|
4296
|
+
return useTranscriptVariant() === "lines";
|
|
4297
|
+
}
|
|
4298
|
+
const DensityContext = createContext("comfortable");
|
|
4299
|
+
function TranscriptDensityProvider({ value, children }) {
|
|
4300
|
+
return /* @__PURE__ */ jsx(DensityContext.Provider, {
|
|
4301
|
+
value,
|
|
4302
|
+
children
|
|
4303
|
+
});
|
|
4304
|
+
}
|
|
4305
|
+
function useTranscriptDensity() {
|
|
4306
|
+
return useContext(DensityContext);
|
|
4307
|
+
}
|
|
4308
|
+
/**
|
|
4309
|
+
* The gap between two rows, per variant and density — the whole of the density
|
|
4310
|
+
* feature, since it is the only vertical spacing between rows that exists.
|
|
4311
|
+
*
|
|
4312
|
+
* `className` goes on the **measured** wrapper (see `Transcript`), so the gap is
|
|
4313
|
+
* part of each row's measured height and no pixel constant is load-bearing.
|
|
4314
|
+
* `px` is fed to `estimateSize` alone, where being approximate is the contract:
|
|
4315
|
+
* it sets the scrollbar's length before rows mount and is replaced by a real
|
|
4316
|
+
* measurement the moment one does.
|
|
4317
|
+
*
|
|
4318
|
+
* `lines` + `compact` is the only combination with no gap at all: there the
|
|
4319
|
+
* row's own `py-0.5` is the entire separation, which is what makes it compact.
|
|
4320
|
+
*/
|
|
4321
|
+
const ROW_GAP = {
|
|
4322
|
+
cards: {
|
|
4323
|
+
comfortable: {
|
|
4324
|
+
className: "pt-4",
|
|
4325
|
+
px: 16
|
|
4326
|
+
},
|
|
4327
|
+
compact: {
|
|
4328
|
+
className: "pt-2",
|
|
4329
|
+
px: 8
|
|
4330
|
+
}
|
|
4331
|
+
},
|
|
4332
|
+
lines: {
|
|
4333
|
+
comfortable: {
|
|
4334
|
+
className: "pt-4",
|
|
4335
|
+
px: 16
|
|
4336
|
+
},
|
|
4337
|
+
compact: { px: 0 }
|
|
4338
|
+
}
|
|
4339
|
+
};
|
|
4340
|
+
/**
|
|
4341
|
+
* The left gutter of a line item: one glyph, fixed width, so every row's text
|
|
4342
|
+
* starts on the same column no matter which kind of event it is. Decorative —
|
|
4343
|
+
* the row's own text says what it is.
|
|
4344
|
+
*/
|
|
4345
|
+
function LineGlyph({ children, className }) {
|
|
4346
|
+
return /* @__PURE__ */ jsx("span", {
|
|
4347
|
+
"aria-hidden": true,
|
|
4348
|
+
className: cn("w-3.5 shrink-0 select-none text-center font-mono text-label leading-5 text-fg-4", className),
|
|
4349
|
+
children
|
|
4350
|
+
});
|
|
4351
|
+
}
|
|
4352
|
+
/** Body text metrics for a line item — tighter than the card variant's. */
|
|
4353
|
+
const LINE_TEXT = "text-body-sm leading-5";
|
|
4354
|
+
//#endregion
|
|
4283
4355
|
//#region src/components/agent/Composer.tsx
|
|
4284
4356
|
/** CLI names may carry display annotations (e.g. "foo (MCP)") the parser rejects. */
|
|
4285
4357
|
const cleanName = (name) => name.replace(/\s*\(MCP\)$/i, "");
|
|
@@ -4332,6 +4404,7 @@ function matchScore(query, haystacks) {
|
|
|
4332
4404
|
*/
|
|
4333
4405
|
function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message the agent…", commands, skills, onSearchFiles, attachments, toolbar, layout = "stacked", className, ref }) {
|
|
4334
4406
|
const inline = layout === "inline";
|
|
4407
|
+
const lines = useLines();
|
|
4335
4408
|
const { bind, plainText, isEmpty, clear, focus } = usePromptAreaState();
|
|
4336
4409
|
const fileInput = useRef(null);
|
|
4337
4410
|
const [dragging, setDragging] = useState(false);
|
|
@@ -4509,7 +4582,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
4509
4582
|
setDragging(false);
|
|
4510
4583
|
pick(e.dataTransfer.files);
|
|
4511
4584
|
},
|
|
4512
|
-
className: cn("mx-auto w-full max-w-[var(--wd-content-max-w,48rem)] overflow-hidden
|
|
4585
|
+
className: cn("mx-auto w-full max-w-[var(--wd-content-max-w,48rem)] overflow-hidden border border-border bg-bg", "transition-colors", lines ? "rounded-sm focus-within:border-accent" : cn("rounded-lg shadow-(--shadow-xs)", "focus-within:border-ring focus-within:ring-2 focus-within:ring-ring/30"), dragging && (lines ? "border-accent" : "border-ring ring-2 ring-ring/30"), disabled && "opacity-60"),
|
|
4513
4586
|
children: [staged.length > 0 && attachments ? /* @__PURE__ */ jsx(AttachmentStrip, { attachments }) : null, inline ? /* @__PURE__ */ jsxs("div", {
|
|
4514
4587
|
className: "flex items-end gap-1 p-1",
|
|
4515
4588
|
children: [
|
|
@@ -4562,11 +4635,7 @@ function Composer({ onSend, onInterrupt, busy, disabled, placeholder = "Message
|
|
|
4562
4635
|
children: /* @__PURE__ */ jsx(X, { className: "size-3" })
|
|
4563
4636
|
})
|
|
4564
4637
|
]
|
|
4565
|
-
}) :
|
|
4566
|
-
"data-slot": "composer-hint",
|
|
4567
|
-
className: "mx-auto mt-1 w-full max-w-[var(--wd-content-max-w,48rem)] text-center text-label text-fg-4",
|
|
4568
|
-
children: "Enter to send · Shift+Enter for a new line"
|
|
4569
|
-
})]
|
|
4638
|
+
}) : null]
|
|
4570
4639
|
});
|
|
4571
4640
|
}
|
|
4572
4641
|
/**
|
|
@@ -5557,36 +5626,6 @@ function isMutatingTool(toolName) {
|
|
|
5557
5626
|
}
|
|
5558
5627
|
}
|
|
5559
5628
|
//#endregion
|
|
5560
|
-
//#region src/components/agent/transcript-variant.tsx
|
|
5561
|
-
const VariantContext = createContext("cards");
|
|
5562
|
-
function TranscriptVariantProvider({ value, children }) {
|
|
5563
|
-
return /* @__PURE__ */ jsx(VariantContext.Provider, {
|
|
5564
|
-
value,
|
|
5565
|
-
children
|
|
5566
|
-
});
|
|
5567
|
-
}
|
|
5568
|
-
function useTranscriptVariant() {
|
|
5569
|
-
return useContext(VariantContext);
|
|
5570
|
-
}
|
|
5571
|
-
/** True in `lines`, for the many `cond ? a : b` reads in the row components. */
|
|
5572
|
-
function useLines() {
|
|
5573
|
-
return useTranscriptVariant() === "lines";
|
|
5574
|
-
}
|
|
5575
|
-
/**
|
|
5576
|
-
* The left gutter of a line item: one glyph, fixed width, so every row's text
|
|
5577
|
-
* starts on the same column no matter which kind of event it is. Decorative —
|
|
5578
|
-
* the row's own text says what it is.
|
|
5579
|
-
*/
|
|
5580
|
-
function LineGlyph({ children, className }) {
|
|
5581
|
-
return /* @__PURE__ */ jsx("span", {
|
|
5582
|
-
"aria-hidden": true,
|
|
5583
|
-
className: cn("w-3.5 shrink-0 select-none text-center font-mono text-label leading-5 text-fg-4", className),
|
|
5584
|
-
children
|
|
5585
|
-
});
|
|
5586
|
-
}
|
|
5587
|
-
/** Body text metrics for a line item — tighter than the card variant's. */
|
|
5588
|
-
const LINE_TEXT = "text-body-sm leading-5";
|
|
5589
|
-
//#endregion
|
|
5590
5629
|
//#region src/components/agent/Response.tsx
|
|
5591
5630
|
/**
|
|
5592
5631
|
* Markdown on a terminal's grid.
|
|
@@ -5759,7 +5798,7 @@ function LineOptionList({ options, focused, onFocus, onChoose, active = true, la
|
|
|
5759
5798
|
className: cn("flex w-full items-baseline gap-2 text-left outline-none", isFocused ? "bg-surface-hover" : "hover:bg-surface-hover/60"),
|
|
5760
5799
|
children: [
|
|
5761
5800
|
/* @__PURE__ */ jsx(LineGlyph, {
|
|
5762
|
-
className: isFocused ? "text-
|
|
5801
|
+
className: isFocused ? "text-fg-1" : void 0,
|
|
5763
5802
|
children: isFocused ? "❯" : " "
|
|
5764
5803
|
}),
|
|
5765
5804
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -5799,7 +5838,7 @@ function LineInput({ value, onChange, onSubmit, onCancel, placeholder }) {
|
|
|
5799
5838
|
return /* @__PURE__ */ jsxs("div", {
|
|
5800
5839
|
className: "flex items-baseline gap-2",
|
|
5801
5840
|
children: [/* @__PURE__ */ jsx(LineGlyph, {
|
|
5802
|
-
className: "text-
|
|
5841
|
+
className: "text-fg-3",
|
|
5803
5842
|
children: "›"
|
|
5804
5843
|
}), /* @__PURE__ */ jsx("input", {
|
|
5805
5844
|
autoFocus: true,
|
|
@@ -6217,7 +6256,7 @@ function QuestionPrompt({ request, onAnswer, onDismiss, className }) {
|
|
|
6217
6256
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
6218
6257
|
className: "flex items-baseline gap-2",
|
|
6219
6258
|
children: [/* @__PURE__ */ jsx(LineGlyph, {
|
|
6220
|
-
className: "text-
|
|
6259
|
+
className: "text-fg-3",
|
|
6221
6260
|
children: "?"
|
|
6222
6261
|
}), /* @__PURE__ */ jsxs("span", {
|
|
6223
6262
|
className: "min-w-0 flex-1 text-body-sm leading-5 text-fg-1",
|
|
@@ -6666,7 +6705,7 @@ function Slot({ onClick, hint, children }) {
|
|
|
6666
6705
|
children
|
|
6667
6706
|
});
|
|
6668
6707
|
}
|
|
6669
|
-
function StatusBar({ state, connected, connection, onOpenStatus, onOpenContext, onOpenUsage, actions, className }) {
|
|
6708
|
+
function StatusBar({ state, connected, connection, onOpenStatus, onOpenContext, onOpenUsage, actions, placement = "top", className }) {
|
|
6670
6709
|
const meta = STATUS_META[state.status];
|
|
6671
6710
|
const now = useNow();
|
|
6672
6711
|
const session = state.rateLimits?.five_hour;
|
|
@@ -6674,7 +6713,7 @@ function StatusBar({ state, connected, connection, onOpenStatus, onOpenContext,
|
|
|
6674
6713
|
const link = connection ?? (connected === false ? "reconnecting" : "live");
|
|
6675
6714
|
return /* @__PURE__ */ jsxs("div", {
|
|
6676
6715
|
"data-slot": "status-bar",
|
|
6677
|
-
className: cn("flex items-center gap-2 border-
|
|
6716
|
+
className: cn("flex items-center gap-2 border-border bg-surface px-3 py-1.5", placement === "bottom" ? "border-t" : "border-b", className),
|
|
6678
6717
|
children: [
|
|
6679
6718
|
/* @__PURE__ */ jsx(Slot, {
|
|
6680
6719
|
onClick: onOpenStatus,
|
|
@@ -6818,27 +6857,68 @@ function FileCard({ item, href, className }) {
|
|
|
6818
6857
|
});
|
|
6819
6858
|
}
|
|
6820
6859
|
//#endregion
|
|
6821
|
-
//#region src/components/agent/
|
|
6860
|
+
//#region src/components/agent/pulse.tsx
|
|
6822
6861
|
/**
|
|
6823
|
-
* The
|
|
6862
|
+
* The brand mark's pulse, as characters — the working marker every surface in the
|
|
6863
|
+
* transcript animates.
|
|
6824
6864
|
*
|
|
6825
|
-
*
|
|
6826
|
-
*
|
|
6827
|
-
*
|
|
6828
|
-
*
|
|
6829
|
-
*
|
|
6865
|
+
* These are the mark's own four states (`docs/assets/BRAND.md`, "The loading
|
|
6866
|
+
* state"): a dot, an outline, a semi and a full diamond, built in the SVG from
|
|
6867
|
+
* two shapes rather than four drawings. 150ms each, so one cycle is the 0.6s
|
|
6868
|
+
* clock the marker pulses on in `icon-loading.svg` — the same rhythm, in the
|
|
6869
|
+
* medium a transcript row actually has.
|
|
6870
|
+
*
|
|
6871
|
+
* BRAND.md's caveat applies and is satisfied here: `U+25C6/7/8` are East-Asian
|
|
6872
|
+
* *ambiguous width*, so they can render double-width in a terminal under an
|
|
6873
|
+
* East-Asian locale and shift every line with them. They are safe wherever the
|
|
6874
|
+
* glyph is centred in a fixed-width box, which is what `LineGlyph` is. Anything
|
|
6875
|
+
* writing to a real terminal must use the ASCII set instead.
|
|
6830
6876
|
*/
|
|
6831
|
-
const
|
|
6832
|
-
"
|
|
6833
|
-
"
|
|
6834
|
-
"
|
|
6835
|
-
"
|
|
6836
|
-
"✽",
|
|
6837
|
-
"✻",
|
|
6838
|
-
"✶",
|
|
6839
|
-
"✳"
|
|
6877
|
+
const PULSE_FRAMES = [
|
|
6878
|
+
"⋄",
|
|
6879
|
+
"◇",
|
|
6880
|
+
"◈",
|
|
6881
|
+
"◆"
|
|
6840
6882
|
];
|
|
6841
|
-
|
|
6883
|
+
/**
|
|
6884
|
+
* The resting state. Stopping the animation lands on the complete mark rather
|
|
6885
|
+
* than on a half-drawn frame — the same property that makes the SVG's
|
|
6886
|
+
* `prefers-reduced-motion` free (see BRAND.md: `translateY(0)` *is* the mark).
|
|
6887
|
+
*/
|
|
6888
|
+
const PULSE_REST = PULSE_FRAMES[PULSE_FRAMES.length - 1];
|
|
6889
|
+
/** The OS-level "stop moving things" setting. A spinner is decoration — the word
|
|
6890
|
+
* beside it carries the meaning — so honouring this costs nothing. */
|
|
6891
|
+
function usePrefersReducedMotion() {
|
|
6892
|
+
const [reduced, setReduced] = useState(false);
|
|
6893
|
+
useEffect(() => {
|
|
6894
|
+
const query = window.matchMedia?.("(prefers-reduced-motion: reduce)");
|
|
6895
|
+
if (!query) return;
|
|
6896
|
+
setReduced(query.matches);
|
|
6897
|
+
const onChange = () => setReduced(query.matches);
|
|
6898
|
+
query.addEventListener("change", onChange);
|
|
6899
|
+
return () => query.removeEventListener("change", onChange);
|
|
6900
|
+
}, []);
|
|
6901
|
+
return reduced;
|
|
6902
|
+
}
|
|
6903
|
+
/**
|
|
6904
|
+
* The current pulse frame, ticking while `animated`. Callers mount this only
|
|
6905
|
+
* while something is actually in flight, so nothing here runs on an idle
|
|
6906
|
+
* session; with reduced motion, or when not animating, it holds at rest.
|
|
6907
|
+
*/
|
|
6908
|
+
function usePulse(animated) {
|
|
6909
|
+
const reduced = usePrefersReducedMotion();
|
|
6910
|
+
const running = animated && !reduced;
|
|
6911
|
+
const [frame, setFrame] = useState(0);
|
|
6912
|
+
useEffect(() => {
|
|
6913
|
+
if (!running) return;
|
|
6914
|
+
const timer = setInterval(() => setFrame((f) => f + 1), 150);
|
|
6915
|
+
return () => clearInterval(timer);
|
|
6916
|
+
}, [running]);
|
|
6917
|
+
if (!running) return PULSE_REST;
|
|
6918
|
+
return PULSE_FRAMES[frame % PULSE_FRAMES.length];
|
|
6919
|
+
}
|
|
6920
|
+
//#endregion
|
|
6921
|
+
//#region src/components/agent/Loader.tsx
|
|
6842
6922
|
/**
|
|
6843
6923
|
* What it says it is doing while it hasn't said anything yet. Cycled on a slow
|
|
6844
6924
|
* clock so a long turn doesn't sit under one frozen word — a still label reads
|
|
@@ -6859,42 +6939,17 @@ const VERBS = [
|
|
|
6859
6939
|
"Noodling"
|
|
6860
6940
|
];
|
|
6861
6941
|
const VERB_MS = 4e3;
|
|
6862
|
-
/** Ticks while mounted, at the spinner's rate. Mounted only while a turn is in
|
|
6863
|
-
* flight, so nothing here runs on an idle session. */
|
|
6864
|
-
function useFrames(animated) {
|
|
6865
|
-
const [frame, setFrame] = useState(0);
|
|
6866
|
-
useEffect(() => {
|
|
6867
|
-
if (!animated) return;
|
|
6868
|
-
const timer = setInterval(() => setFrame((f) => f + 1), FRAME_MS);
|
|
6869
|
-
return () => clearInterval(timer);
|
|
6870
|
-
}, [animated]);
|
|
6871
|
-
return frame;
|
|
6872
|
-
}
|
|
6873
|
-
/** The OS-level "stop moving things" setting. A spinner is decoration; the word
|
|
6874
|
-
* beside it carries the meaning, so honouring this costs nothing. */
|
|
6875
|
-
function usePrefersReducedMotion() {
|
|
6876
|
-
const [reduced, setReduced] = useState(false);
|
|
6877
|
-
useEffect(() => {
|
|
6878
|
-
const query = window.matchMedia?.("(prefers-reduced-motion: reduce)");
|
|
6879
|
-
if (!query) return;
|
|
6880
|
-
setReduced(query.matches);
|
|
6881
|
-
const onChange = () => setReduced(query.matches);
|
|
6882
|
-
query.addEventListener("change", onChange);
|
|
6883
|
-
return () => query.removeEventListener("change", onChange);
|
|
6884
|
-
}, []);
|
|
6885
|
-
return reduced;
|
|
6886
|
-
}
|
|
6887
6942
|
/**
|
|
6888
6943
|
* "The agent is working and hasn't produced output yet."
|
|
6889
6944
|
*
|
|
6890
|
-
* `lines`: a terminal working line —
|
|
6891
|
-
* the readings that answer "should I still be
|
|
6892
|
-
* `cards`: the three-dot pulse, unchanged
|
|
6945
|
+
* `lines`: a terminal working line — the mark's own pulse in the gutter (see
|
|
6946
|
+
* `pulse.tsx`), a verb, and the readings that answer "should I still be
|
|
6947
|
+
* waiting?" in one parenthesis. `cards`: the three-dot pulse, unchanged — the
|
|
6948
|
+
* dashboard's loader is not a gutter glyph and has no column to pulse in.
|
|
6893
6949
|
*/
|
|
6894
6950
|
function Loader({ label, startedAt, tokens, className }) {
|
|
6895
6951
|
const lines = useLines();
|
|
6896
|
-
const
|
|
6897
|
-
const frame = useFrames(lines && !reducedMotion);
|
|
6952
|
+
const pulse = usePulse(lines);
|
|
6898
6953
|
if (!lines) return /* @__PURE__ */ jsxs("div", {
|
|
6899
6954
|
"data-slot": "loader",
|
|
6900
6955
|
className: cn("flex items-center gap-2 py-1 text-body-sm text-fg-4", className),
|
|
@@ -6917,8 +6972,8 @@ function Loader({ label, startedAt, tokens, className }) {
|
|
|
6917
6972
|
"data-slot": "loader",
|
|
6918
6973
|
className: cn("flex items-baseline gap-2", className),
|
|
6919
6974
|
children: [/* @__PURE__ */ jsx(LineGlyph, {
|
|
6920
|
-
className: "text-accent",
|
|
6921
|
-
children:
|
|
6975
|
+
className: lines ? "text-fg-3" : "text-accent",
|
|
6976
|
+
children: pulse
|
|
6922
6977
|
}), /* @__PURE__ */ jsxs("span", {
|
|
6923
6978
|
className: "min-w-0 flex-1 text-body-sm leading-5 text-fg-3",
|
|
6924
6979
|
children: [
|
|
@@ -6942,9 +6997,12 @@ function Loader({ label, startedAt, tokens, className }) {
|
|
|
6942
6997
|
/**
|
|
6943
6998
|
* One chat turn row.
|
|
6944
6999
|
*
|
|
6945
|
-
* `cards`: user messages sit
|
|
6946
|
-
* full-width
|
|
6947
|
-
*
|
|
7000
|
+
* `cards`: user messages sit in a bubble, assistant content is flat and
|
|
7001
|
+
* full-width. Both are **left-aligned**: the transcript is a log read top to
|
|
7002
|
+
* bottom, and an editor-shaped host (a full-width session view beside a sessions
|
|
7003
|
+
* rail) has no right edge to anchor to — a bubble drifting right in a 1600px
|
|
7004
|
+
* column separates a prompt from the reply it produced. The bubble alone is
|
|
7005
|
+
* enough to say who spoke.
|
|
6948
7006
|
*
|
|
6949
7007
|
* `lines`: both are left-aligned full-width line items behind a gutter glyph —
|
|
6950
7008
|
* `❯` for what was typed, `●` for what the model said. No bubble: a prompt is
|
|
@@ -6956,10 +7014,10 @@ function Message({ from, className, children, ...props }) {
|
|
|
6956
7014
|
return /* @__PURE__ */ jsx("div", {
|
|
6957
7015
|
"data-slot": "message",
|
|
6958
7016
|
"data-from": from,
|
|
6959
|
-
className: cn("flex w-full", lines ? cn("flex-row gap-2", from === "user" && "-mx-1 rounded-sm bg-surface px-1") :
|
|
7017
|
+
className: cn("flex w-full", lines ? cn("flex-row gap-2", from === "user" && "-mx-1 rounded-sm bg-surface px-1") : "flex-col items-start gap-1", className),
|
|
6960
7018
|
...props,
|
|
6961
7019
|
children: lines ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(LineGlyph, {
|
|
6962
|
-
className: from === "user" ? "text-
|
|
7020
|
+
className: from === "user" ? "text-fg-2" : "text-fg-3",
|
|
6963
7021
|
children: from === "user" ? "❯" : "●"
|
|
6964
7022
|
}), /* @__PURE__ */ jsx("div", {
|
|
6965
7023
|
className: "flex min-w-0 flex-1 flex-col gap-1",
|
|
@@ -6970,7 +7028,7 @@ function Message({ from, className, children, ...props }) {
|
|
|
6970
7028
|
function MessageContent({ className, ...props }) {
|
|
6971
7029
|
return /* @__PURE__ */ jsx("div", {
|
|
6972
7030
|
"data-slot": "message-content",
|
|
6973
|
-
className: cn("min-w-0", useLines() ? cn("w-full text-fg-1", LINE_TEXT, "in-data-[from=user]:whitespace-pre-wrap") : cn("text-body-sm leading-6 text-fg-1", "in-data-[from=user]:max-w-[85%] in-data-[from=user]:rounded-lg in-data-[from=user]:rounded-
|
|
7031
|
+
className: cn("min-w-0", useLines() ? cn("w-full text-fg-1", LINE_TEXT, "in-data-[from=user]:whitespace-pre-wrap") : cn("text-body-sm leading-6 text-fg-1", "in-data-[from=user]:max-w-[85%] in-data-[from=user]:rounded-lg in-data-[from=user]:rounded-bl-sm", "in-data-[from=user]:bg-accent-bg in-data-[from=user]:px-3 in-data-[from=user]:py-2", "in-data-[from=user]:whitespace-pre-wrap", "in-data-[from=assistant]:w-full"), className),
|
|
6974
7032
|
...props
|
|
6975
7033
|
});
|
|
6976
7034
|
}
|
|
@@ -7229,6 +7287,7 @@ function ToolCallCard({ item, hostImage, className }) {
|
|
|
7229
7287
|
const status = item.status ?? (item.result === void 0 ? "running" : "settled");
|
|
7230
7288
|
const badge = STATE_BADGE[status];
|
|
7231
7289
|
const isError = status === "failed" || item.result?.isError === true;
|
|
7290
|
+
const pulse = usePulse(lines && badge.busy);
|
|
7232
7291
|
const Icon = toolIcon(item.name);
|
|
7233
7292
|
const resultText = item.result?.text ?? "";
|
|
7234
7293
|
const truncated = !fullResult && resultText.length > RESULT_PREVIEW_CHARS;
|
|
@@ -7284,7 +7343,7 @@ function ToolCallCard({ item, hostImage, className }) {
|
|
|
7284
7343
|
children: [
|
|
7285
7344
|
/* @__PURE__ */ jsx(LineGlyph, {
|
|
7286
7345
|
className: status === "settled" && !isError && isMutatingTool(item.name) ? "text-success" : STATE_GLYPH[status],
|
|
7287
|
-
children: badge.busy ?
|
|
7346
|
+
children: badge.busy ? pulse : "●"
|
|
7288
7347
|
}),
|
|
7289
7348
|
/* @__PURE__ */ jsxs("span", {
|
|
7290
7349
|
className: "min-w-0 flex-1 truncate text-body-sm leading-5 text-fg-3",
|
|
@@ -7304,7 +7363,6 @@ function ToolCallCard({ item, hostImage, className }) {
|
|
|
7304
7363
|
className: "shrink-0 text-label text-fg-4",
|
|
7305
7364
|
children: item.backend
|
|
7306
7365
|
}) : null,
|
|
7307
|
-
badge.busy ? /* @__PURE__ */ jsx(Spinner, { className: "size-3 shrink-0 self-center text-fg-4" }) : null,
|
|
7308
7366
|
status === "deferred" ? /* @__PURE__ */ jsx(Clock, { className: "size-3 shrink-0 self-center text-fg-4" }) : null,
|
|
7309
7367
|
isError && !badge.busy ? /* @__PURE__ */ jsx("span", {
|
|
7310
7368
|
className: "shrink-0 text-label text-danger",
|
|
@@ -7556,7 +7614,7 @@ function RecapRow({ line, since }) {
|
|
|
7556
7614
|
"data-slot": "recap",
|
|
7557
7615
|
className: "flex items-baseline gap-2 py-0.5",
|
|
7558
7616
|
children: [/* @__PURE__ */ jsx(LineGlyph, {
|
|
7559
|
-
className: "text-
|
|
7617
|
+
className: "text-fg-3",
|
|
7560
7618
|
children: "※"
|
|
7561
7619
|
}), /* @__PURE__ */ jsxs("span", {
|
|
7562
7620
|
className: "min-w-0 flex-1 text-label leading-5 text-fg-3",
|
|
@@ -7652,7 +7710,7 @@ function showLoader(state) {
|
|
|
7652
7710
|
* References only — the bytes are fetched from the gateway. */
|
|
7653
7711
|
function SentAttachments({ attachments, attachmentUrl }) {
|
|
7654
7712
|
return /* @__PURE__ */ jsx("div", {
|
|
7655
|
-
className:
|
|
7713
|
+
className: "mb-1 flex flex-wrap justify-start gap-1.5",
|
|
7656
7714
|
children: attachments.map((attachment) => {
|
|
7657
7715
|
const href = attachmentUrl?.(attachment.id);
|
|
7658
7716
|
return attachment.mediaType.startsWith("image/") && href ? /* @__PURE__ */ jsx("img", {
|
|
@@ -7707,7 +7765,7 @@ function nestedClass(item, lines) {
|
|
|
7707
7765
|
* transient UI state (an expanded tool card, an opened reasoning block) resets
|
|
7708
7766
|
* once the row scrolls far enough away to unmount.
|
|
7709
7767
|
*/
|
|
7710
|
-
function TranscriptRows({ rows, boundary, since, lines, fileUrl, attachmentUrl, hostImage, jumpToRecapRef }) {
|
|
7768
|
+
function TranscriptRows({ rows, boundary, since, lines, gap, fileUrl, attachmentUrl, hostImage, jumpToRecapRef }) {
|
|
7711
7769
|
const stick = useStickToBottomContext();
|
|
7712
7770
|
const [scrollElement, setScrollElement] = useState(null);
|
|
7713
7771
|
useEffect(() => {
|
|
@@ -7719,7 +7777,7 @@ function TranscriptRows({ rows, boundary, since, lines, fileUrl, attachmentUrl,
|
|
|
7719
7777
|
if (scrollElement && virtualizer.scrollElement !== scrollElement) virtualizer.scrollOffset = scrollElement.scrollTop;
|
|
7720
7778
|
return scrollElement;
|
|
7721
7779
|
},
|
|
7722
|
-
estimateSize: () => lines ? 32 : 100,
|
|
7780
|
+
estimateSize: () => (lines ? 32 : 100) + gap.px,
|
|
7723
7781
|
overscan: 8,
|
|
7724
7782
|
getItemKey: (index) => rows[index].key,
|
|
7725
7783
|
useFlushSync: true
|
|
@@ -7769,7 +7827,7 @@ function TranscriptRows({ rows, boundary, since, lines, fileUrl, attachmentUrl,
|
|
|
7769
7827
|
return /* @__PURE__ */ jsx("div", {
|
|
7770
7828
|
ref: virtualizer.measureElement,
|
|
7771
7829
|
"data-index": virtualRow.index,
|
|
7772
|
-
className: cn("absolute inset-x-0 top-0",
|
|
7830
|
+
className: cn("absolute inset-x-0 top-0", virtualRow.index > 0 && gap.className),
|
|
7773
7831
|
style: { transform: `translateY(${virtualRow.start}px)` },
|
|
7774
7832
|
children: "item" in row ? /* @__PURE__ */ jsx("div", {
|
|
7775
7833
|
className: cn(lines && "-mx-1 rounded-sm px-1 py-0.5 transition-colors hover:bg-surface-hover", boundary !== void 0 && row.index < boundary && "opacity-45", nestedClass(row.item, lines)),
|
|
@@ -7787,8 +7845,9 @@ function TranscriptRows({ rows, boundary, since, lines, fileUrl, attachmentUrl,
|
|
|
7787
7845
|
})
|
|
7788
7846
|
});
|
|
7789
7847
|
}
|
|
7790
|
-
function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage, variant = "cards", catchUp, jumpToRecapRef, className }) {
|
|
7848
|
+
function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage, variant = "cards", density = "comfortable", catchUp, jumpToRecapRef, className }) {
|
|
7791
7849
|
const lines = variant === "lines";
|
|
7850
|
+
const gap = ROW_GAP[variant][density];
|
|
7792
7851
|
const runStartedAt = useRunStart(state.status);
|
|
7793
7852
|
const following = useSettled(state.items.length, state.status);
|
|
7794
7853
|
const boundary = catchUp && catchUp.from > 0 && catchUp.from < state.items.length ? catchUp.from : void 0;
|
|
@@ -7829,6 +7888,7 @@ function Transcript({ state, fileUrl, attachmentUrl, canBrowseFiles, hostImage,
|
|
|
7829
7888
|
boundary,
|
|
7830
7889
|
since: catchUp?.since,
|
|
7831
7890
|
lines,
|
|
7891
|
+
gap,
|
|
7832
7892
|
fileUrl,
|
|
7833
7893
|
attachmentUrl,
|
|
7834
7894
|
hostImage,
|
|
@@ -7992,7 +8052,7 @@ const INTERACTIVE = [
|
|
|
7992
8052
|
* the engine name — an absent capability hides the control instead of offering
|
|
7993
8053
|
* one that can only fail.
|
|
7994
8054
|
*/
|
|
7995
|
-
function SessionPanel({ client, sessionId, header, panelSurface = "internal", statusSurface = "internal", onOpenPanel, onVitals, transcriptVariant = "cards", controlsSurface = "internal", onControls, focusComposerOnClick = false, unseen, className }) {
|
|
8055
|
+
function SessionPanel({ client, sessionId, header, panelSurface = "internal", statusSurface = "internal", statusPlacement = "top", onOpenPanel, onVitals, transcriptVariant = "cards", transcriptDensity = "comfortable", controlsSurface = "internal", onControls, focusComposerOnClick = false, unseen, readOnly = false, className }) {
|
|
7996
8056
|
const external = panelSurface === "external";
|
|
7997
8057
|
const statusExternal = statusSurface === "external";
|
|
7998
8058
|
const controlsExternal = controlsSurface === "external";
|
|
@@ -8068,7 +8128,8 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
8068
8128
|
const controls = useRef({
|
|
8069
8129
|
setModel: (model) => setters.current.setModel(model),
|
|
8070
8130
|
setPermissionMode: (mode) => setters.current.setPermissionMode(mode),
|
|
8071
|
-
interrupt: () => setters.current.interrupt()
|
|
8131
|
+
interrupt: () => setters.current.interrupt(),
|
|
8132
|
+
focusComposer: () => composerRef.current?.focus()
|
|
8072
8133
|
});
|
|
8073
8134
|
useEffect(() => {
|
|
8074
8135
|
const handler = onControlsRef.current;
|
|
@@ -8143,176 +8204,183 @@ function SessionPanel({ client, sessionId, header, panelSurface = "internal", st
|
|
|
8143
8204
|
] })] });
|
|
8144
8205
|
const menu = external ? null : actionsMenu;
|
|
8145
8206
|
const headerTakesActions = typeof header === "function";
|
|
8207
|
+
const statusBar = statusExternal ? null : /* @__PURE__ */ jsx(StatusBar, {
|
|
8208
|
+
state,
|
|
8209
|
+
connection,
|
|
8210
|
+
placement: statusPlacement,
|
|
8211
|
+
onOpenStatus: external && !onOpenPanel ? void 0 : () => openPanel("info"),
|
|
8212
|
+
onOpenContext: external && !onOpenPanel ? void 0 : () => openPanel("context"),
|
|
8213
|
+
onOpenUsage: external && !onOpenPanel ? void 0 : () => openPanel("usage"),
|
|
8214
|
+
actions: headerTakesActions ? void 0 : menu
|
|
8215
|
+
});
|
|
8146
8216
|
const handleClick = (event) => {
|
|
8147
|
-
if (!focusComposerOnClick) return;
|
|
8217
|
+
if (!focusComposerOnClick || readOnly) return;
|
|
8148
8218
|
if (event.target?.closest(INTERACTIVE)) return;
|
|
8149
8219
|
if (window.getSelection()?.isCollapsed === false) return;
|
|
8150
8220
|
composerRef.current?.focus();
|
|
8151
8221
|
};
|
|
8152
8222
|
return /* @__PURE__ */ jsx(TranscriptVariantProvider, {
|
|
8153
8223
|
value: transcriptVariant,
|
|
8154
|
-
children: /* @__PURE__ */
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8165
|
-
onOpenUsage: external && !onOpenPanel ? void 0 : () => openPanel("usage"),
|
|
8166
|
-
actions: headerTakesActions ? void 0 : menu
|
|
8167
|
-
}),
|
|
8168
|
-
protocolMismatch !== void 0 ? /* @__PURE__ */ jsxs(Notice, {
|
|
8169
|
-
level: "warning",
|
|
8170
|
-
children: [
|
|
8171
|
-
"Server speaks protocol v",
|
|
8172
|
-
protocolMismatch,
|
|
8173
|
-
", this build renders v",
|
|
8174
|
-
PROTOCOL_VERSION,
|
|
8175
|
-
". Some events may not render."
|
|
8176
|
-
]
|
|
8177
|
-
}) : null,
|
|
8178
|
-
protocolError ? /* @__PURE__ */ jsx(Notice, {
|
|
8179
|
-
level: "error",
|
|
8180
|
-
onDismiss: () => setProtocolError(void 0),
|
|
8181
|
-
children: protocolError
|
|
8182
|
-
}) : null,
|
|
8183
|
-
/* @__PURE__ */ jsx(Transcript, {
|
|
8184
|
-
state,
|
|
8185
|
-
fileUrl: sessionId ? (path) => client.sessionFileUrl(sessionId, path) : void 0,
|
|
8186
|
-
attachmentUrl: sessionId ? (id) => client.attachmentUrl(sessionId, id) : void 0,
|
|
8187
|
-
canBrowseFiles: hostFiles.available,
|
|
8188
|
-
hostImage,
|
|
8189
|
-
variant: transcriptVariant,
|
|
8190
|
-
catchUp: catchUp && newCount > 0 ? {
|
|
8191
|
-
from: catchUp.itemCount,
|
|
8192
|
-
since: catchUp.since
|
|
8193
|
-
} : void 0,
|
|
8194
|
-
jumpToRecapRef: jumpToRecap
|
|
8195
|
-
}),
|
|
8196
|
-
catchUp && newCount > 0 ? /* @__PURE__ */ jsx("div", {
|
|
8197
|
-
className: "px-3 pb-1",
|
|
8198
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
8199
|
-
"data-slot": "catch-up",
|
|
8200
|
-
className: "mx-auto flex w-full max-w-[var(--wd-content-max-w,48rem)] items-center gap-2 text-label text-fg-3",
|
|
8224
|
+
children: /* @__PURE__ */ jsx(TranscriptDensityProvider, {
|
|
8225
|
+
value: transcriptDensity,
|
|
8226
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
8227
|
+
"data-slot": "session-panel",
|
|
8228
|
+
onClick: handleClick,
|
|
8229
|
+
className: cn("flex h-full min-h-0 flex-col overflow-hidden bg-bg", className),
|
|
8230
|
+
children: [
|
|
8231
|
+
headerTakesActions ? header({ actions: menu }) : header,
|
|
8232
|
+
statusPlacement === "top" ? statusBar : null,
|
|
8233
|
+
protocolMismatch !== void 0 ? /* @__PURE__ */ jsxs(Notice, {
|
|
8234
|
+
level: "warning",
|
|
8201
8235
|
children: [
|
|
8202
|
-
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
|
|
8207
|
-
/* @__PURE__ */ jsxs("span", {
|
|
8208
|
-
className: "min-w-0 flex-1 truncate",
|
|
8209
|
-
children: [
|
|
8210
|
-
newCount,
|
|
8211
|
-
" new ",
|
|
8212
|
-
newCount === 1 ? "row" : "rows",
|
|
8213
|
-
catchUp.since !== void 0 ? ` since you were last here` : ""
|
|
8214
|
-
]
|
|
8215
|
-
}),
|
|
8216
|
-
/* @__PURE__ */ jsx("button", {
|
|
8217
|
-
type: "button",
|
|
8218
|
-
onClick: () => jumpToRecap.current?.(),
|
|
8219
|
-
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
8220
|
-
children: "jump"
|
|
8221
|
-
}),
|
|
8222
|
-
/* @__PURE__ */ jsx("button", {
|
|
8223
|
-
type: "button",
|
|
8224
|
-
onClick: () => setCaughtUp(true),
|
|
8225
|
-
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
8226
|
-
children: "dismiss"
|
|
8227
|
-
})
|
|
8236
|
+
"Server speaks protocol v",
|
|
8237
|
+
protocolMismatch,
|
|
8238
|
+
", this build renders v",
|
|
8239
|
+
PROTOCOL_VERSION,
|
|
8240
|
+
". Some events may not render."
|
|
8228
8241
|
]
|
|
8229
|
-
})
|
|
8230
|
-
|
|
8231
|
-
|
|
8232
|
-
|
|
8233
|
-
|
|
8234
|
-
|
|
8235
|
-
|
|
8236
|
-
request,
|
|
8237
|
-
onAnswer: approve,
|
|
8238
|
-
onDismiss: (id) => deny(id, "Question dismissed by user")
|
|
8239
|
-
}, request.id) : /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
8240
|
-
request,
|
|
8241
|
-
onApprove: approve,
|
|
8242
|
-
onDeny: deny
|
|
8243
|
-
}, request.id))
|
|
8244
|
-
})
|
|
8245
|
-
}) : null,
|
|
8246
|
-
/* @__PURE__ */ jsx(Composer, {
|
|
8247
|
-
ref: composerRef,
|
|
8248
|
-
onSend: handleSend,
|
|
8249
|
-
onInterrupt: interrupt,
|
|
8250
|
-
busy,
|
|
8251
|
-
disabled: ended || !sessionId,
|
|
8252
|
-
commands: capabilities.slashCommands ? commands : void 0,
|
|
8253
|
-
skills: capabilities.skillsList ? state.skills : void 0,
|
|
8254
|
-
attachments,
|
|
8255
|
-
onSearchFiles: hostFiles.available ? (query, options) => hostFiles.search(query, {
|
|
8256
|
-
...options,
|
|
8257
|
-
limit: 8
|
|
8258
|
-
}) : void 0,
|
|
8259
|
-
layout: controlsExternal ? "inline" : "stacked",
|
|
8260
|
-
toolbar: controlsExternal ? void 0 : /* @__PURE__ */ jsxs(Fragment$1, { children: [models.length ? /* @__PURE__ */ jsx(ModelSelect, {
|
|
8261
|
-
models,
|
|
8262
|
-
model: effectiveModel,
|
|
8263
|
-
onModelChange: setModel,
|
|
8264
|
-
disabled: ended
|
|
8265
|
-
}) : null, state.permissionMode ? /* @__PURE__ */ jsx(PermissionModeSelect, {
|
|
8266
|
-
mode: state.permissionMode,
|
|
8267
|
-
onModeChange: setPermissionMode,
|
|
8268
|
-
modes: capabilities.permissionModes,
|
|
8269
|
-
canBypass: state.session?.canBypassPermissions,
|
|
8270
|
-
disabled: ended
|
|
8271
|
-
}) : null] })
|
|
8272
|
-
}),
|
|
8273
|
-
!external ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
8274
|
-
/* @__PURE__ */ jsx(SessionInfoDialog, {
|
|
8242
|
+
}) : null,
|
|
8243
|
+
protocolError ? /* @__PURE__ */ jsx(Notice, {
|
|
8244
|
+
level: "error",
|
|
8245
|
+
onDismiss: () => setProtocolError(void 0),
|
|
8246
|
+
children: protocolError
|
|
8247
|
+
}) : null,
|
|
8248
|
+
/* @__PURE__ */ jsx(Transcript, {
|
|
8275
8249
|
state,
|
|
8276
|
-
client,
|
|
8277
|
-
sessionId,
|
|
8278
|
-
|
|
8279
|
-
|
|
8250
|
+
fileUrl: sessionId ? (path) => client.sessionFileUrl(sessionId, path) : void 0,
|
|
8251
|
+
attachmentUrl: sessionId ? (id) => client.attachmentUrl(sessionId, id) : void 0,
|
|
8252
|
+
canBrowseFiles: hostFiles.available,
|
|
8253
|
+
hostImage,
|
|
8254
|
+
variant: transcriptVariant,
|
|
8255
|
+
density: transcriptDensity,
|
|
8256
|
+
catchUp: catchUp && newCount > 0 ? {
|
|
8257
|
+
from: catchUp.itemCount,
|
|
8258
|
+
since: catchUp.since
|
|
8259
|
+
} : void 0,
|
|
8260
|
+
jumpToRecapRef: jumpToRecap
|
|
8280
8261
|
}),
|
|
8281
|
-
/* @__PURE__ */ jsx(
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
|
|
8294
|
-
|
|
8295
|
-
|
|
8296
|
-
|
|
8297
|
-
|
|
8298
|
-
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8262
|
+
catchUp && newCount > 0 ? /* @__PURE__ */ jsx("div", {
|
|
8263
|
+
className: "px-3 pb-1",
|
|
8264
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
8265
|
+
"data-slot": "catch-up",
|
|
8266
|
+
className: "mx-auto flex w-full max-w-[var(--wd-content-max-w,48rem)] items-center gap-2 text-label text-fg-3",
|
|
8267
|
+
children: [
|
|
8268
|
+
/* @__PURE__ */ jsx("span", {
|
|
8269
|
+
"aria-hidden": true,
|
|
8270
|
+
className: cn("select-none", transcriptVariant === "lines" ? "text-fg-3" : "text-accent"),
|
|
8271
|
+
children: "※"
|
|
8272
|
+
}),
|
|
8273
|
+
/* @__PURE__ */ jsxs("span", {
|
|
8274
|
+
className: "min-w-0 flex-1 truncate",
|
|
8275
|
+
children: [
|
|
8276
|
+
newCount,
|
|
8277
|
+
" new ",
|
|
8278
|
+
newCount === 1 ? "row" : "rows",
|
|
8279
|
+
catchUp.since !== void 0 ? ` since you were last here` : ""
|
|
8280
|
+
]
|
|
8281
|
+
}),
|
|
8282
|
+
/* @__PURE__ */ jsx("button", {
|
|
8283
|
+
type: "button",
|
|
8284
|
+
onClick: () => jumpToRecap.current?.(),
|
|
8285
|
+
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
8286
|
+
children: "jump"
|
|
8287
|
+
}),
|
|
8288
|
+
/* @__PURE__ */ jsx("button", {
|
|
8289
|
+
type: "button",
|
|
8290
|
+
onClick: () => setCaughtUp(true),
|
|
8291
|
+
className: "shrink-0 underline-offset-2 hover:text-fg-1 hover:underline",
|
|
8292
|
+
children: "dismiss"
|
|
8293
|
+
})
|
|
8294
|
+
]
|
|
8295
|
+
})
|
|
8296
|
+
}) : null,
|
|
8297
|
+
!readOnly && capabilities.interactiveApprovals && state.pendingApprovals.length > 0 ? /* @__PURE__ */ jsx("div", {
|
|
8298
|
+
className: "px-3 pb-2",
|
|
8299
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
8300
|
+
className: "mx-auto flex w-full max-w-[var(--wd-content-max-w,48rem)] flex-col gap-2",
|
|
8301
|
+
children: state.pendingApprovals.map((request) => request.toolName === "AskUserQuestion" && parseUserQuestions(request.input).length > 0 ? /* @__PURE__ */ jsx(QuestionPrompt, {
|
|
8302
|
+
request,
|
|
8303
|
+
onAnswer: approve,
|
|
8304
|
+
onDismiss: (id) => deny(id, "Question dismissed by user")
|
|
8305
|
+
}, request.id) : /* @__PURE__ */ jsx(PermissionPrompt, {
|
|
8306
|
+
request,
|
|
8307
|
+
onApprove: approve,
|
|
8308
|
+
onDeny: deny
|
|
8309
|
+
}, request.id))
|
|
8310
|
+
})
|
|
8311
|
+
}) : null,
|
|
8312
|
+
readOnly ? null : /* @__PURE__ */ jsx(Composer, {
|
|
8313
|
+
ref: composerRef,
|
|
8314
|
+
onSend: handleSend,
|
|
8315
|
+
onInterrupt: interrupt,
|
|
8316
|
+
busy,
|
|
8317
|
+
disabled: ended || !sessionId,
|
|
8318
|
+
commands: capabilities.slashCommands ? commands : void 0,
|
|
8319
|
+
skills: capabilities.skillsList ? state.skills : void 0,
|
|
8320
|
+
attachments,
|
|
8321
|
+
onSearchFiles: hostFiles.available ? (query, options) => hostFiles.search(query, {
|
|
8322
|
+
...options,
|
|
8323
|
+
limit: 8
|
|
8324
|
+
}) : void 0,
|
|
8325
|
+
layout: controlsExternal ? "inline" : "stacked",
|
|
8326
|
+
toolbar: controlsExternal ? void 0 : /* @__PURE__ */ jsxs(Fragment$1, { children: [models.length ? /* @__PURE__ */ jsx(ModelSelect, {
|
|
8327
|
+
models,
|
|
8328
|
+
model: effectiveModel,
|
|
8329
|
+
onModelChange: setModel,
|
|
8330
|
+
disabled: ended
|
|
8331
|
+
}) : null, state.permissionMode ? /* @__PURE__ */ jsx(PermissionModeSelect, {
|
|
8332
|
+
mode: state.permissionMode,
|
|
8333
|
+
onModeChange: setPermissionMode,
|
|
8334
|
+
modes: capabilities.permissionModes,
|
|
8335
|
+
canBypass: state.session?.canBypassPermissions,
|
|
8336
|
+
disabled: ended
|
|
8337
|
+
}) : null] })
|
|
8307
8338
|
}),
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8339
|
+
statusPlacement === "bottom" ? statusBar : null,
|
|
8340
|
+
!external ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
8341
|
+
/* @__PURE__ */ jsx(SessionInfoDialog, {
|
|
8342
|
+
state,
|
|
8343
|
+
client,
|
|
8344
|
+
sessionId,
|
|
8345
|
+
open: panel === "info",
|
|
8346
|
+
onOpenChange: (next) => setPanel(next ? "info" : void 0)
|
|
8347
|
+
}),
|
|
8348
|
+
/* @__PURE__ */ jsx(ContextDialog, {
|
|
8349
|
+
usage: state.contextUsage,
|
|
8350
|
+
open: panel === "context",
|
|
8351
|
+
onOpenChange: (next) => setPanel(next ? "context" : void 0)
|
|
8352
|
+
}),
|
|
8353
|
+
/* @__PURE__ */ jsx(UsageDialog, {
|
|
8354
|
+
rateLimits: windows,
|
|
8355
|
+
subscriptionType: state.subscriptionType,
|
|
8356
|
+
engine: state.engine ?? "claude",
|
|
8357
|
+
totalCostUsd: state.totalCostUsd,
|
|
8358
|
+
updatedAt: state.rateLimitsUpdatedAt,
|
|
8359
|
+
open: panel === "usage",
|
|
8360
|
+
onOpenChange: (next) => setPanel(next ? "usage" : void 0)
|
|
8361
|
+
}),
|
|
8362
|
+
/* @__PURE__ */ jsx(McpDialog, {
|
|
8363
|
+
client,
|
|
8364
|
+
sessionId,
|
|
8365
|
+
canManageServers: capabilities.mcpServerActions,
|
|
8366
|
+
open: panel === "mcp",
|
|
8367
|
+
onOpenChange: (next) => setPanel(next ? "mcp" : void 0)
|
|
8368
|
+
}),
|
|
8369
|
+
/* @__PURE__ */ jsx(SkillsDialog, {
|
|
8370
|
+
skills: state.skills,
|
|
8371
|
+
open: panel === "skills",
|
|
8372
|
+
onOpenChange: (next) => setPanel(next ? "skills" : void 0),
|
|
8373
|
+
onUse: (skill) => composerRef.current?.insertText(skillPrompt(skill))
|
|
8374
|
+
}),
|
|
8375
|
+
/* @__PURE__ */ jsx(HostFilesDialog, {
|
|
8376
|
+
client,
|
|
8377
|
+
cwd: state.cwd,
|
|
8378
|
+
open: panel === "files",
|
|
8379
|
+
onOpenChange: (next) => setPanel(next ? "files" : void 0)
|
|
8380
|
+
})
|
|
8381
|
+
] }) : null
|
|
8382
|
+
]
|
|
8383
|
+
})
|
|
8316
8384
|
})
|
|
8317
8385
|
});
|
|
8318
8386
|
}
|
|
@@ -8404,6 +8472,6 @@ function Notice({ level, onDismiss, children }) {
|
|
|
8404
8472
|
});
|
|
8405
8473
|
}
|
|
8406
8474
|
//#endregion
|
|
8407
|
-
export {
|
|
8475
|
+
export { Tip as $, SkillsDialog as A, commandTrigger as B, isMutatingTool as C, Button as Ct, permissionModeChoices as D, PermissionModeSelect as E, skillPrompt as F, plainTextToSegments as G, mentionTrigger as H, TranscriptDensityProvider as I, Splitter as J, segmentsToPlainText as K, TranscriptVariantProvider as L, HostFilesDialog as M, ContextDialog as N, permissionModeMeta as O, Composer as P, copyText as Q, useTranscriptDensity as R, Response as S, badgeVariants as St, PERMISSION_MODES as T, cn as Tt, usePromptAreaState as U, hashtagTrigger as V, PromptArea as W, Spinner as X, CodeBlock as Y, CopyButton as Z, SessionInfoDialog as _, SelectItemText as _t, SessionEmptyState as a, DialogContent as at, parseUserQuestions as b, Input as bt, Message as c, DialogTrigger as ct, FileCard as d, MenuItem as dt, TooltipContent as et, Conversation as f, MenuSeparator as ft, STATUS_META as g, SelectItem as gt, StatusBar as h, SelectContent as ht, ToolCallCard as i, DialogClose as it, McpDialog as j, ModelSelect as k, MessageContent as l, Menu$1 as lt, ConversationScrollButton as m, Select$1 as mt, UsageDialog as n, Dialog$1 as nt, Reasoning as o, DialogHeader as ot, ConversationContent as p, MenuTrigger as pt, ProgressRing as q, Transcript as r, DialogBody as rt, PromptTokenText as s, DialogRow as st, SessionPanel as t, TooltipProvider as tt, Loader as u, MenuContent as ut, QUESTION_BEHAVIORS as v, SelectTrigger as vt, toolIcon as w, buttonVariants as wt, PermissionPrompt as x, Badge as xt, QuestionPrompt as y, SelectValue as yt, useTranscriptVariant as z };
|
|
8408
8476
|
|
|
8409
|
-
//# sourceMappingURL=SessionPanel-
|
|
8477
|
+
//# sourceMappingURL=SessionPanel-CKQa4i0Y.mjs.map
|